#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""dispatcher related class 分流平台类
@author : buptzjj 
@license : Copyright@haohandata
@version : 1.0
@todo : 创建脚本  20170728  by buptzjj
        修改为支持多板卡模式 20171104 by buptzjj
        修正恒为分流采集的正则表达式  20191104 by buptzjj
@require : 要求Python2.6支持OrderedDict，否则执行会报错        
"""

import subprocess
import get_snmp_info
import os
import time
import re

plugins_path = os.getenv("INSPECTOR_HOME") + "/plugins"
try:
    from collections import OrderedDict as ordict
except ImportError:
    import ordereddict as ordict

ERR_FLAG = "No Such"

div_list = [
    {"name": "锐安", "oid": ".1.3.6.1.4.1.35030.5"},
    {"name": "恒为", "oid": "1.3.6.1.4.1.1013.1"},
    {"name": "华3", "oid": ".1.3.6.1.2.1.2.2"}
]


class DispatchPlatform(object):
    def __init__(self, ip, password):
        self.ip = ip
        self.password = password

    def get_mac_address(self):
        command = "arp -a %s" % (self.ip)
        result = subprocess.run(
            command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
        status = result.returncode
        output = result.stdout.decode("utf-8")
        if 0 == status and self.ip in output:
            pattern = re.compile(r"[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){5}")
            match = pattern.search(output)
            mac_addr = match.group()
            return mac_addr
        else:
            return None

    def get_serial_number(self):
        return None

    def get_if_num(self):
        return None

    def get_if_name(self):
        return []

    def get_if_bandwidth(self):
        return []

    def get_if_status(self):
        return []

    def get_if_in_traffic(self):
        return []

    def get_if_out_traffic(self):
        return []

    def get_if_in_pps(self):
        return []

    def get_if_out_pps(self):
        return []

    def get_if_in_err_pkts(self):
        return []

    def get_if_out_err_pkts(self):
        return []

    def get_if_in_err_fcs_pkts(self):
        return []

    def get_if_out_err_fcs_pkts(self):
        return []

    def get_sys_info(self):
        return None

    def get_subboard_type(self):
        return []

    def get_subboard_status(self):
        return []


class DivOptiway(DispatchPlatform):
    def __init__(self, ip, password):
        super(DivOptiway, self).__init__(ip, password)
        self.board_num = 0
        self.if_map = {}

    def __map_status(self, x):
        return "UP" if int(x) == 1 else "DOWN"

    def _get_all_board_info(self, regex):
        start_time = int(time.time())
        if self.board_num == 0:
            self.board_num = int(get_if_num(self.ip, "1.3.6.1.4.1.1013.2.1"))
            self.if_map = build_if_map(self.ip, "1.3.6.1.4.1.1013.2")
        if_info = []
        for key in self.if_map:
            if re.search(regex, key):
                if_info.append(self.if_map[key])
        finish_time = int(time.time())
        # print('{0}-{1} cost {2}s'.format(self.ip, regex, (finish_time-start_time)))
        return if_info

    def get_if_num(self):
        return get_if_num(self.ip, "1.3.6.1.2.1.2.1")

    def get_serial_number(self):
        command = "expect %s/collect/optiway_login.exp %s %s" % (
            plugins_path,
            self.ip,
            self.password,
        )
        result = subprocess.run(
            command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
        status = result.returncode
        output = result.stdout.decode("utf-8")
        if 0 == status:
            lines = output.split("\n")
            for line in lines:
                if str(line).startswith("product_serial_number"):
                    segs = line.split("=")
                    return str(segs[1]).strip() if len(segs) > 0 else None
        return None

    def get_sys_info(self):
        return get_if_info(self.ip, "1.3.6.1.4.1.1013.1")

    def get_if_name(self):
        oid_format = "^.*.1013.2.*.*.2.2.1.3\..*"
        return self._get_all_board_info(oid_format)

    def get_if_bandwidth(self):
        oid_format = "^.*.1013.2.*.*.2.2.1.6\..*"
        return self._get_all_board_info(oid_format)

    def get_if_status(self):
        oid_format = "^.*.1013.2.*.*.2.2.1.8\..*"
        status_list = self._get_all_board_info(oid_format)
        return map(self.__map_status, status_list)

    def get_if_in_traffic(self):
        # 直接取到的就是速率值，单位Kbps
        oid_format = "^.*.1013.2.*.*.2.2.1.11\..*"
        return self._get_all_board_info(oid_format)

    def get_if_out_traffic(self):
        # 直接取到的就是速率值，单位Kbps
        oid_format = "^.*.1013.2.*.*.2.2.1.12\..*"
        return self._get_all_board_info(oid_format)

    def get_if_in_pps(self):
        # 直接取到的就是速率值，单位Kbps
        oid_format = "^.*.1013.2.*.*.2.2.1.27\..*"
        return self._get_all_board_info(oid_format)

    def get_if_out_pps(self):
        # 直接取到的就是速率值，单位Kbps
        oid_format = "^.*.1013.2.*.*.2.2.1.28\..*"
        return self._get_all_board_info(oid_format)

    def get_subboard_type(self):
        oid_format = "^.*.1013.2.[1-9]\d*.1.1.2.1.*"
        return self._get_all_board_info(oid_format)

    def get_subboard_status(self):
        oid_format = "^.*.1013.2.[1-9]\d*.1.1.3.1.*"
        return self._get_all_board_info(oid_format)

    def get_if_in_err_pkts(self):
        # 直接取到的是累加报文数
        oid_format = "^.*.1013.2.*.*.2.2.1.17\..*"
        return self._get_all_board_info(oid_format)

    def get_if_out_err_pkts(self):
        # 直接取到的是累加报文数
        oid_format = "^.*.1013.2.*.*.2.2.1.24\..*"
        return self._get_all_board_info(oid_format)

    def get_if_in_err_fcs_pkts(self):
        # 直接取到的是累加报文数
        oid_format = "^.*.1013.2.*.*.2.2.1.18\..*"
        return self._get_all_board_info(oid_format)

    def get_if_out_err_fcs_pkts(self):
        # 直接取到的是累加报文数
        oid_format = "^.*.1013.2.*.*.2.2.1.25\..*"
        return self._get_all_board_info(oid_format)


class DivRuian(DispatchPlatform):
    def __init__(self, ip, password):
        super(DivRuian, self).__init__(ip, password)
        self.if_num = 0

    def __map_status(self, x):
        return "UP" if int(x) == 1 else "DOWN"

    def __map_bandwidth(self, x):
        if x == "1G":
            return 1 * 1000 * 1000 * 1000
        elif x == "10G":
            return 10 * 1000 * 1000 * 1000
        elif x == "20G":
            return 20 * 1000 * 1000 * 1000
        elif x == "40G":
            return 10 * 1000 * 1000 * 1000
        elif x == "100G":
            return 100 * 1000 * 1000 * 1000
        else:
            return 1 * 1000 * 1000 * 1000

    def get_if_num(self):
        return len(get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.2"))

    def get_if_name(self):
        return get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.2")

    def get_if_bandwidth(self):
        return map(
            self.__map_bandwidth, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.4")
        )

    def get_if_status(self):
        return map(self.__map_status, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.3"))

    def get_if_in_traffic(self):
        # 直接取到的是流量Byte/s，需要换算为kbps
        return map(
            lambda x: int(x) * 8 / 1000,
            get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.6"),
        )

    def get_if_out_traffic(self):
        return map(
            lambda x: int(x) * 8 / 1000,
            get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.8"),
        )

    def get_if_in_pps(self):
        # 直接取到的是包速率
        return map(int, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.16"))

    def get_if_out_pps(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.19"))

    def get_if_in_err_pkts(self):
        # 直接取到的是累加报文数
        return map(int, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.10"))

    def get_if_out_err_pkts(self):
        # 直接取到的是累加报文数
        return map(int, get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.12"))

    def get_subboard_type(self):
        # TODO: 新版锐安分流未提供此接口，用板卡名称代替
        return get_if_info(self.ip, ".1.3.6.1.4.1.35030.6.1.2")

    def get_subboard_status(self):
        # TODO: 新版锐安分流未提供此接口，用板卡名称代替
        return get_if_info(self.ip, ".1.3.6.1.4.1.35030.6.1.2")

    def get_if_in_err_fcs_pkts(self):
        # 直接取到的是累加报文数
        return len(get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.2")) * [0]

    def get_if_out_err_fcs_pkts(self):
        # 直接取到的是累加报文数
        return len(get_if_info(self.ip, ".1.3.6.1.4.1.35030.5.1.2")) * [0]


def get_if_info(ip, oid):
    (status, output) = get_snmp_info.get_snmp_info(ip, oid)
    if_info_list = []
    if 0 == status and ERR_FLAG not in output:
        lines = output.split("\n")
        for line in lines:
            if "=" in line:
                val = line.split(":")[-1].strip().strip('"')
                if_info_list.append(val)
    return if_info_list


def build_if_map(ip, oid):
    if_map = ordict()
    (status, output) = get_snmp_info.get_snmp_info(ip, oid)
    if_info_list = []
    if 0 == status and ERR_FLAG not in output:
        lines = output.split("\n")
        for line in lines:
            if "=" in line:
                val = line.split(":")[-1].strip().strip('"')
                if_map[line.split("=")[0].strip()] = val
    return if_map


def get_manufacturer(ip):
    for div in div_list:
        (status, output) = get_snmp_info.get_snmp_info(ip, div["oid"])
        if 0 == status and ERR_FLAG not in output:
            return div["name"]
    return "未知"


def get_if_num(ip, oid):
    (status, output) = get_snmp_info.get_snmp_info(ip, oid)
    if 0 == status and ERR_FLAG not in output:
        result = str(output).strip().split(":")
        return result[len(result) - 1].strip()


def hexstr2str(data):
    return "".join(chr(int(data[i: i + 2], 16)) for i in range(0, len(data), 3)).strip(
        "\x00"
    )


class DivH3CSwitch(DispatchPlatform):
    """ 华3类交换机  """
    def __init__(self, ip, password):
        super(DivH3CSwitch, self).__init__(ip, password)
        self.if_num = 0

    def __map_status(self, x):
        return "UP" if int(x) == 1 else "DOWN"

    def __map_bandwidth(self, x):
        if x == "1G":
            return 1 * 1000 * 1000 * 1000
        elif x == "10G":
            return 10 * 1000 * 1000 * 1000
        elif x == "20G":
            return 20 * 1000 * 1000 * 1000
        elif x == "40G":
            return 10 * 1000 * 1000 * 1000
        elif x == "100G":
            return 100 * 1000 * 1000 * 1000
        else:
            return 1 * 1000 * 1000 * 1000

    """
    接口数目    ifNumber		OID	 .1.3.6.1.2.1.2.1
    """
    def get_if_num(self):
        return len(get_if_info(self.ip, ".1.3.6.1.2.1.2.1"))

    """
    接口名称    ifName			OID	 .1.3.6.1.2.1.31.1.1.1.1
    """
    def get_if_name(self):
        return get_if_info(self.ip, ".1.3.6.1.2.1.31.1.1.1.1")

    """
    接口当前带宽估计（单位为Mbs）    ifHighSpeed		OID	 .1.3.6.1.2.1.31.1.1.1.15
    接口速率    ifSpeed			OID	 .1.3.6.1.2.1.2.2.1.5
    """
    def get_if_bandwidth(self):
        return map(
            self.__map_bandwidth, get_if_info(self.ip, ".1.3.6.1.2.1.31.1.1.1.15")
        )

    """
    接口当前运行状态    ifOperStatus	OID	 .1.3.6.1.2.1.2.2.1.8
    """
    def get_if_status(self):
        return map(self.__map_status, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.8"))

    """
    接口输入字节数 ifInOctets		OID	 .1.3.6.1.2.1.2.2.1.10
    """
    def get_if_in_traffic(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.10"))

    """
    接口输出字节数 ifOutOctets		OID	 .1.3.6.1.2.1.2.2.1.16
    """
    def get_if_out_traffic(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.16"))

    """
    接口输入单播包数    ifInUcastPkts	OID	 .1.3.6.1.2.1.2.2.1.11
    """
    def get_if_in_pps(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.11"))

    """
    接口输出单播包数    ifOutUcastPkts	OID	 .1.3.6.1.2.1.2.2.1.17
    """
    def get_if_out_pps(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.17"))

    """
    接口输入包错误数 ifInErrors		OID	 .1.3.6.1.2.1.2.2.1.14
    """
    def get_if_in_err_pkts(self):
        return map(int, get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.14"))

    """
    接口输出包错误数    ifOutErrors		OID	 .1.3.6.1.2.1.2.2.1.20
    """
    def get_if_out_err_pkts(self):
        return map(int, get_if_info(self.ip, "1.3.6.1.2.1.2.2.1.20"))

    """
    接口类型 ifType			OID	 .1.3.6.1.2.1.2.2.1.3
    """
    def get_subboard_type(self):
        return get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.3")

    """
    接口管理状态  ifAdminStatus	OID	 .1.3.6.1.2.1.2.2.1.7
    """
    def get_subboard_status(self):
        return get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.7")

    """
    接口输入非单播包数   ifInNUcastPkts	OID	 .1.3.6.1.2.1.2.2.1.12
    """
    def get_if_in_err_fcs_pkts(self):
        return len(get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.12")) * [0]

    """
    接口输出非单播包数   ifOutNUcastPkts	OID	 .1.3.6.1.2.1.2.2.1.18
    """
    def get_if_out_err_fcs_pkts(self):
        return len(get_if_info(self.ip, ".1.3.6.1.2.1.2.2.1.18")) * [0]
